/*****	CATALOG >>> contains information on Catalog File, containing Number of Tables, Tables List *****/
class catalog {
	char	catalog_file[FILE_NAME_LENGTH];
	int	num_of_tables;
	table 	*tlist;				// list of tables in this catalog
	buffer	*buf_mgr;			// one buffer for each catalog
	stm	*stm_catalog;			// to read and write to a catalog file
	class my_index	*tbl_index ;

	int read_catalog_file();
public:
	catalog(char *catalog_file, int num_blocks);
	~catalog();

	int add_table(tableinfo *tbl1);
	int insert_record(char *tablename, int numvalues, int *arr);
	int select_records(char *tablename, int num, char *attribnames, clause *qry);
	int create_index(char *tname, char *iname, char *attrib, int dup_flag);
	int commit();


	/*** to print the information abuot the catalog ***/
	int 	print();
	int	print(char *tablename);
	int	print_index(char *iname);
	void	print_buffers();
	int	print_hit_rate();

};

catalog :: catalog(char *filename, int num_blocks)
{
	strcpy(catalog_file, filename);
	buf_mgr 	= new buffer(num_blocks);
	stm_catalog 	= new stm(catalog_file);
	tbl_index 	= new my_index();
	tlist		= NULL;

	read_catalog_file();	
}

int catalog :: read_catalog_file()
{
	tableinfo tinfo;
	int	i=0, offset=0;
	int	num=0;

	if(DISK_FILE == stm_catalog->get_file_type())
	{
		stm_catalog->read_buffer(0, (char *) &num, sizeof(num));
		offset += sizeof(num);
		for(i=0; i<num; i++)
		{
			stm_catalog->read_buffer(offset, (char *)&tinfo, sizeof(tableinfo));
			DBGPRINTN(tinfo.num_of_records);
			add_table(&tinfo);
			offset += sizeof(tableinfo);
		}
		DBGPRINTF("DISK CATALOG FILE: %d tables are created using the catalog file\n", num);
		return(0);

	}
	else {
		DBGPRINTF("NEW CATALOG FILE: there are no tables created yet\n");
		return(0);
	}
}


int catalog :: add_table( tableinfo *tinfo1)
{

	table *t1=NULL, *temp=NULL;

	DBGPRINTN(tinfo1->num_of_attribs);
	DBGPRINTS(tbl_index);

	/***  Check if Table exists already ***/
	if( NULL != tbl_index->get_key(tinfo1->table_name) )
	{
		FATAL("Table %s already present in the database\n",tinfo1->table_name);
		return(INVALID_DATA);
	}

	t1 =  new table(tinfo1, buf_mgr);
	DBGPRINTS(t1->get_table_name());
	tbl_index->insert_key(tinfo1->table_name, (void *) t1);

	/*** Adding to the list of tables ***/
	if(tlist == NULL)
	{
		tlist = t1;
	} else {
		temp = tlist;
		while(temp->next!=NULL)	
		{
			temp=temp->next;
			DBGPRINTN(temp->next);
		}
		temp->next = t1;
	}


	DBGPRINTS(t1->get_table_name());
	
	num_of_tables++;
	return(0);
}

int catalog :: insert_record(char *tablename, int numvalues, int *arr)
{

	table *t1;
	if( NULL == (t1 = (table *) tbl_index->get_key(tablename)) )
	{
		FATAL("Table key not found for %s\n", tablename);
		DBGPRINTN(numvalues);
		DBGPRINTS(tablename);
		return DATA_NOT_FOUND;
	}

	DBGPRINTN(numvalues);
	if(numvalues != t1->no_of_attribs())
	{
		FATAL("No. of values not equal to No. of attribs\n");
		DBGPRINTN(numvalues);
		DBGPRINTS(tablename);
		DBGPRINTN(t1->no_of_attribs());
		return DATA_NOT_FOUND;
	}

	t1->insert_record(arr);
	return(0);
}

int catalog :: select_records(char *tablename, int num, char *attribnames, clause *qry)
{
	table *t1;

	if( NULL == (t1 = (table *) tbl_index->get_key(tablename)) )
	{
		FATAL("Table key not found for %s\n", tablename);
		DBGPRINTS(tablename);
		return DATA_NOT_FOUND;
	}

	if(t1->print_attriblist(num, attribnames, qry))
	{
		FATAL("Error in printing the attributelist\n");
		DBGPRINTS(tablename);
		return DATA_NOT_FOUND;

	}

	return(0);
}

int catalog :: create_index(char *tname, char *iname, char *attrib, int dup_flag)
{
	table *t1;

	if( NULL == (t1 = (table *) tbl_index->get_key(tname)) )
	{
		FATAL("Table key not found for %s\n", tname);
		return DATA_NOT_FOUND;
	}

	DBGPRINTS(tname);
	DBGPRINTS(iname);
	DBGPRINTS(attrib);
	if(t1->add_index(iname, attrib, dup_flag))
	{
		FATAL("Error in adding Index for %s in Table %s\n", attrib, tname);
		return(DATA_NOT_FOUND);
	}

	return(0);

}

int catalog :: print()
{
	table *tbl_ptr;

	HEAD("CATALOG >>> %s\n", catalog_file);		
	SHEAD("Number of Tables >>> %d\n", num_of_tables);

	tbl_ptr = tlist;

	while(tbl_ptr!=NULL) {
		tbl_ptr->print_stats();
		tbl_ptr = tbl_ptr->next;
	}

	buf_mgr->print_stats();

	return(0);
}

int catalog :: print(char *tablename)
{
	table *t1;
	if( NULL == (t1 = (table *) tbl_index->get_key(tablename)) )
	{
		FATAL("Table key not found for %s\n", tablename);
		DBGPRINTS(tablename);
		return DATA_NOT_FOUND;
	}

	if(t1->print())
	{
		FATAL("Error in printing table %s\n",tablename);
		return INTERNAL_ERROR;
	}

	return(0);
}

int catalog :: print_index(char *iname)
{
	table *t1;

	t1 = tlist;

	while(t1!=NULL)
	{
		DBGPRINTS(t1->get_table_name());
		if(NULL == t1->find_index(iname))
		{
			t1 =  t1->next;
			continue;
		}
		else
		{
			t1->print_index(iname);
			return(0);
		}
	}

	DBGPRINTS(iname);
	FATAL("Index %s not found\n", iname);
	return(DATA_NOT_FOUND);

}

int catalog :: commit()
{
	table *tbl_ptr;
	int offset = 0;

	buf_mgr->commit();

	stm_catalog->write_buffer( offset, (char *) &num_of_tables, sizeof(num_of_tables));
	offset += sizeof(num_of_tables);

	tbl_ptr = tlist;
	while(tbl_ptr!=NULL)
	{
		tbl_ptr->commit();	

		struct tableinfo *t_info = tbl_ptr->tbl_info();

		DBGPRINTS(tbl_ptr->get_table_name());
		DBGPRINTN(t_info->num_of_records);
		DBGMEMPRINT(t_info,sizeof(struct tableinfo));
		DBGPRINTN(sizeof(struct tableinfo));

		stm_catalog->write_buffer( offset, (char *) t_info, sizeof(struct tableinfo));
		offset += sizeof(tableinfo);
		tbl_ptr =  tbl_ptr->next;
	}

	stm_catalog->flush();

	return(0);

}

int catalog :: print_hit_rate()
{
	buf_mgr->print_stats();
	return(0);
}

/***	1. Commit all the stm, buf_mgr, table classes
	2. Delete all the classes created using new in this file ***/

catalog :: ~catalog()
{
	table *temp, *next;

	commit();
	delete buf_mgr;

	temp = tlist;
	while(temp != NULL)
	{
		next = temp->next;
		delete temp;
		temp = next;
	}

	delete stm_catalog;
	delete tbl_index;

}

void catalog :: print_buffers()
{
	buf_mgr->print();
}
